package com.daikun.common.aop.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.daikun.common.aop.annos.BaseCheckRequestParam;
import com.daikun.common.enums.BaseResultEnum;
import com.daikun.common.iface.BaseParamCheckIface;
import com.daikun.common.iface.I18nMessageIface;
import com.daikun.common.model.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * {@link BaseCheckRequestParam} 注解解析器
 * @author earl created 2025-07-03
 * @version init 0.0.1
 */
@Slf4j
@Aspect
@Component
public class BaseCheckRequestParamHandler {

    @Pointcut("@annotation(com.daikun.common.aop.annos.BaseCheckRequestParam)")
    public void invoke() {}

    @Around("invoke()")
    public Object pointCut(ProceedingJoinPoint point) throws Throwable {
        try {
            MethodSignature target = (MethodSignature) point.getSignature();

            RequestMapping requestMapping = AnnotationUtils.findAnnotation(target.getMethod(), RequestMapping.class);
            if (requestMapping == null) {
                return point.proceed();
            }
            BaseCheckRequestParam check = AnnotationUtils.findAnnotation(target.getMethod(), BaseCheckRequestParam.class);
            Object[] args = point.getArgs();
            if (args == null || args.length == 0) {
                return point.proceed();
            }
            for (Object arg : args) {
                if (!(arg instanceof BaseParamCheckIface)) {
                    continue;
                }
                BaseParamCheckIface param = (BaseParamCheckIface) arg;
                Map<String, String> map = param.checkParam();
                if (CollUtil.isEmpty(map)) {
                    continue;
                }
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (servletRequestAttributes == null || servletRequestAttributes.getResponse() == null) {
                    continue;
                }
                HttpServletResponse response = servletRequestAttributes.getResponse();
                response.setStatus(HttpServletResponse.SC_OK);
                response.setContentType("application/json; charset=utf-8");
                // noinspection DataFlowIssue
                response.getWriter().write(BaseResult.fail(BaseResultEnum.PARAM_ERROR, mapToMsg(map, check)).toString());
                return null;
            }
        } catch (Throwable e) {
            log.info("CheckRequestParamParser.pointCut info -> param check fail, msg = {}", e.getMessage(), e);
        }
        return point.proceed();
    }

    /**
     * 将校验结果的 map 链接成字符串
     * @param map 校验结果
     * @param checkObj 注解
     */
    public static String mapToMsg(Map<String, String> map, BaseCheckRequestParam checkObj) {
        if (!checkObj.showInfo()) {
            I18nMessageIface msgBean = SpringUtil.getBean(I18nMessageIface.class);
            if (msgBean == null) {
                return BaseResultEnum.PARAM_ERROR.getMsg();
            }
            String i18nMsg = msgBean.getI18nMsg(BaseResultEnum.PARAM_ERROR.getCode());
            if (StrUtil.isBlank(i18nMsg)) {
                return BaseResultEnum.PARAM_ERROR.getMsg();
            }
            return i18nMsg;
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("; ");
        }
        return sb.length() > 2 ? sb.substring(0, sb.length() - 2) : sb.toString();
    }
}
